// Copyright (c) <2010> <Playdead>
// This file is subject to the MIT License as seen in the trunk of this repository
// Maintained by: <Kristian Kjems> <kristian.kjems+UnitySVN@gmail.com>

// The script overrides Unity's inspector for GameObjects to include the state
// of the resource on the repository.
// SVNCommands is used to get state and execute commands on the repository.


#define SVN_ENABLED
#define SVN_OBJECT_ACTION_ENABLED
#if (SVN_ENABLED)
using UnityEngine;
using UnityEditor;
using System.Collections;
using SVNIntegrationNameSpace;

#pragma warning disable 0219, 0414

[CustomEditor(typeof(GameObject))]
public class SVNLock_GameObject : Editor
{
    SVNStatus svnStatus = new SVNStatus();
    string assetpath = "";
    static string svnCommitMessage = "";
    bool svnBusy = false;

    void OnEnable()
    {
        RefreshFromDatabase();
        SVNIntegration.instance.SVNDatabaseUpdated += new SVNIntegration.SVNDatabaseHandler(RefreshGUI);
    }

    void OnDisable()
    {
        SVNIntegration.instance.SVNDatabaseUpdated -= new SVNIntegration.SVNDatabaseHandler(RefreshGUI);
    }

    void RefreshGUI(object source, SVNDatabaseArgs e)
    {
        if (e is SVNDatabaseUpdatedArgs)
        {
            svnBusy = false;
            RefreshFromDatabase();
            this.Repaint();
        }
        if (e is SVNDatabaseBusyArgs)
        {
            svnBusy = true;
            RefreshFromDatabase();
            this.Repaint();
        }
    }

    void RefreshFromDatabase()
    {
        assetpath = SVNUtility.GetAssetPath(target as GameObject);
        svnStatus = SVNCommands.instance.GetAssetStatus(assetpath);
    }


    public override void OnInspectorGUI()
    {
        DrawSVNStatusGUI();
        DrawDefaultGameObjectGUI();
        if (EditorUtility.GetPrefabType(target as GameObject) != PrefabType.None)
        {
            DrawPrefabGUI();
        }
    }

    private bool guiStateIsStatic;
    private int guiStateLayer;
    private string guiStateTag;

    void DrawDefaultGameObjectGUI()
    {

        GameObject go = target as GameObject;
        EditorGUILayout.BeginVertical();
        EditorGUILayout.BeginHorizontal();
        GUILayout.Label(new GUIContent("Static", "Shift click to apply setting to all children"), EditorStyles.miniLabel); guiStateIsStatic = GUILayout.Toggle(go.isStatic, "", EditorStyles.toggle);
        if (guiStateIsStatic != go.isStatic)
        {
            go.isStatic = guiStateIsStatic;
            if (Event.current.shift)
            {
                foreach (Transform childIt in go.GetComponentsInChildren<Transform>())
                {
                    childIt.gameObject.isStatic = guiStateIsStatic;
                }
            }
        }
        GUILayout.Label("Layer", EditorStyles.miniLabel); guiStateLayer = EditorGUILayout.LayerField(go.layer);
        if (guiStateLayer != go.layer) go.layer = guiStateLayer;
        GUILayout.Label("Tag", EditorStyles.miniLabel); guiStateTag = EditorGUILayout.TagField(go.tag);
        if (guiStateTag != go.tag) go.tag = guiStateTag;
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.EndVertical();
    }

    void DrawPrefabGUI()
    {
        GameObject go = target as GameObject;
        PrefabType prefabType = EditorUtility.GetPrefabType(go);
        GameObject prefabParent = EditorUtility.GetPrefabParent(go) as GameObject;


        GUILayoutOption[] buttonLayout = {};
        EditorGUILayout.BeginHorizontal();

        if (prefabParent != null)
        {
            if (GUILayout.Button("Select", buttonLayout))
            {
                Selection.activeGameObject = prefabParent;
            }
        }
        if (prefabType == PrefabType.PrefabInstance || prefabType == PrefabType.ModelPrefabInstance)
        {
            if (GUILayout.Button("Revert", buttonLayout))
            {
                EditorUtility.ResetGameObjectToPrefabState(go);
            }
        }
        if (prefabType == PrefabType.PrefabInstance)
        {
            if (GUILayout.Button("Apply", buttonLayout))
            {
                EditorUtility.ReplacePrefab(go, prefabParent, ReplacePrefabOptions.UseLastUploadedPrefabRoot);                
                EditorUtility.ResetGameObjectToPrefabState(go);
                AssetDatabase.SaveAssets();
                EditorUtility.UnloadUnusedAssets();
                SVNCommands.instance.UpdateLocalSVNStatus();
            }
        }
        if (prefabType == PrefabType.DisconnectedPrefabInstance)
        {
            if (GUILayout.Button("Revert", buttonLayout))
            {
                EditorUtility.ReconnectToLastPrefab(go);
            }
            if (GUILayout.Button("Apply", buttonLayout))
            {
                EditorUtility.ReplacePrefab(go, prefabParent, ReplacePrefabOptions.UseLastUploadedPrefabRoot);
                EditorUtility.ReconnectToLastPrefab(go);
                AssetDatabase.SaveAssets();
                EditorUtility.UnloadUnusedAssets();
                SVNCommands.instance.UpdateLocalSVNStatus();
            }
        }
        EditorGUILayout.EndHorizontal();
    }

    void DrawSVNStatusGUI()
    {
        GameObject go = target as GameObject;
        PrefabType pbtype = EditorUtility.GetPrefabType(go);
        GameObject prefabRoot = EditorUtility.FindPrefabRoot(go) as GameObject;

        bool shouldLockObject = false;
        bool isManagedByRepository = (svnStatus.reflectionLevel == ESVNReflectionLevel.Repository || svnStatus.reflectionLevel == ESVNReflectionLevel.Local) && svnStatus.fileStatus != ESVNFileStatus.Unversioned;
        bool hasLocalLock = svnStatus.lockStatus == ESVNLockStatus.LockedHere;
        bool isLockByOther = svnStatus.lockStatus == ESVNLockStatus.LockedOther;

        shouldLockObject = !svnStatus.bypassRevisionControl && isManagedByRepository && ((!hasLocalLock && !SVNUtility.ChangesStoredInScene(go)) || isLockByOther);

#if(!SVN_OBJECT_ACTION_ENABLED)
        shouldLockObject = false;
#endif

        if (shouldLockObject)
        {
            go.hideFlags |= HideFlags.NotEditable;
            Repaint();
        }
        else
        {
            go.hideFlags &= ~HideFlags.NotEditable;
            Repaint();
        }

        //GUILayout.Label("prefab type: " + EditorUtility.GetPrefabType(go) + " svn: " + svnStatus.lockStatus);
        EditorGUILayout.BeginHorizontal();
        bool isModified = svnStatus.fileStatus == ESVNFileStatus.Modified;
        GUIContent labelContent = new GUIContent((isModified ? "(M) " : "") + (SVNUtility.ChangesStoredInScene(go) ? "Scene " : "Prefab ") + GetLockStatusMessage(svnStatus), assetpath);
        GUILayout.Label(labelContent, GetLockStatusStyle(svnStatus));
        EditorGUILayout.EndHorizontal();
#if(SVN_OBJECT_ACTION_ENABLED)
        EditorGUILayout.BeginHorizontal();
        GUILayoutOption[] buttonLayout = { GUILayout.Width(60) };
        if (svnStatus.lockStatus == ESVNLockStatus.LockedHere || svnStatus.bypassRevisionControl)
        {
            if (!svnBusy)
            {
                if (GUILayout.Button("Revert", buttonLayout))
                {
                    SVNCommands.instance.SVNRevert(new string[] { assetpath });
                }
                if (!svnStatus.bypassRevisionControl)
                {
                    if (GUILayout.Button("Commit", buttonLayout))
                    {
                        if (!SVNUtility.ChangesStoredInScene(go))
                        {
                            GameObject prefabParent = EditorUtility.GetPrefabParent(go) as GameObject;
                            EditorUtility.ReplacePrefab(go, prefabParent, ReplacePrefabOptions.UseLastUploadedPrefabRoot);
                            EditorUtility.ResetGameObjectToPrefabState(go);
                        }
                        else
                        {
                            EditorApplication.SaveCurrentSceneIfUserWantsTo();
                        }
                        EditorUtility.UnloadUnusedAssets();
                        EditorApplication.SaveAssets();
                        AssetDatabase.SaveAssets();
                        SVNCommands.instance.SVNCommit(new string[] { assetpath }, (svnCommitMessage.Length == 0 ? "Commit from Unity" : svnCommitMessage));
                    }
                    svnCommitMessage = GUILayout.TextField(svnCommitMessage);
                }
            }
        }
        EditorGUILayout.EndHorizontal();
#endif

    }


    GUIStyle GetLockStatusStyle(SVNStatus svnStatus)
    {
        GUIStyle lockStatusStyle = new GUIStyle(EditorStyles.label);
        lockStatusStyle.fontStyle = FontStyle.Bold;
        if (svnStatus.lockStatus == ESVNLockStatus.LockedOther) lockStatusStyle.normal.textColor = new Color(0.8f, 0.1f, 0.1f);
        if (svnStatus.lockStatus == ESVNLockStatus.LockedHere) lockStatusStyle.normal.textColor = new Color(0.0f, 0.4f, 0.0f);
        if (svnStatus.lockStatus == ESVNLockStatus.NoLock) lockStatusStyle.normal.textColor = new Color(0.4f, 0.4f, 0.0f);
        if (svnStatus.bypassRevisionControl) lockStatusStyle.normal.textColor = new Color(0.8f, 0.4f, 0.0f);
        return lockStatusStyle;
    }

    string GetLockStatusMessage(SVNStatus svnStatus)
    {
        string prefabLockMessage = svnStatus.lockStatus.ToString();
        if (svnStatus.lockStatus == ESVNLockStatus.LockedOther) prefabLockMessage = "Locked by: " + svnStatus.owner;
        if (svnStatus.lockStatus == ESVNLockStatus.LockedHere) prefabLockMessage = "Locked Here: " + svnStatus.owner;
        if (svnStatus.lockStatus == ESVNLockStatus.NoLock)
        {
            prefabLockMessage = "Not Locked";
#if(SVN_OBJECT_ACTION_ENABLED)
            prefabLockMessage += "(Ctrl+L to Lock)";
#endif
        }
        if (svnStatus.bypassRevisionControl)
        {
            prefabLockMessage = "Lock bypassed";
            if ((svnStatus.lockStatus == ESVNLockStatus.LockedOther))
            {
                prefabLockMessage += " (Locked By: " + svnStatus.owner + " )";
            }
        }
        return prefabLockMessage;
    }

}

#endif
